package cn.sofwin.core.mvc.web;

import cn.sofwin.core.mvc.bean.info.Module;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;

import cn.sofwin.core.mvc.service.BaseService;
import cn.sofwin.core.utils.bean.IdEntity;
import cn.sofwin.core.mvc.bean.PageParams;
import cn.sofwin.core.utils.common.DataMap;
import cn.sofwin.core.utils.common.DateUtils;
import cn.sofwin.core.utils.common.StringUtils;
import cn.sofwin.core.utils.api.RequestResult;
import cn.sofwin.core.utils.api.StatusCode;
import cn.sofwin.core.utils.db.Page;
import cn.sofwin.core.utils.db.Selector;

/**
 * 实现单表CRUD功能的抽象Controller <br/>
 * @param <T>
 */
@RestController
public abstract class BaseController<T extends IdEntity> {

    /** 实体服务，将会在运行过程中动态从子类对象获取 */
    private BaseService<T> baseService;

    /**
     * 获取实体服务，如果为空则从子类对象中动态获取
     * @return
     */
    private BaseService<T> getService(){
        if(baseService == null){
            try {
                Field[] fields = this.getClass().getDeclaredFields();
                for (Field field : fields){
                    if(field.getAnnotation(cn.sofwin.core.mvc.annotation.BaseService.class) != null){
                        field.setAccessible(true);
                        baseService = (BaseService<T>) field.get(this);
                        break;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            if(baseService == null){
                System.out.println("获取实体服务失败...");
            }
        }

        return baseService;
    }

    /**
     * 获取功能模块信息
     * @return
     */
    @GetMapping("module")
    public RequestResult moduleInfo(){
        RequestResult result = new RequestResult();
        result.appendData("module", getService().loadModuleInfo());
        return result;
    }

    /**
     * 分页查询
     * @param pageParams
     * @param request
     * @return
     */
    @GetMapping("")
    public RequestResult list(
                PageParams pageParams,
                HttpServletRequest request) {

        Selector selector = new Selector();
        parseSearch(selector, pageParams.getSearch()); // 解析查询参数
        beforeList(selector, pageParams, request);
        Page<T> pageResult = getService().find(selector, pageParams);
        List<T> entityList = pageResult.getList();

        RequestResult result = new RequestResult();

        DataMap query = new DataMap();
        query.put("search", pageParams.getSearch());
        query.put("sort", pageParams.getSort());

        result.appendData("query", query);
        result.appendData("page", pageResult.getInfo());
        result.appendData("list", entityList);
        Module module = getService().loadModuleInfo();
        result.appendData("columns", module.getMeta().getColumns());
        result.appendData("searchFields", module.getSearchFields());

        afterList(entityList, pageParams, request, result);

        return result;
    }

    /**
     * 根据ID查找
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public RequestResult findById(@PathVariable("id") Integer id){
        T bean = getService().get(id);
        RequestResult result = new RequestResult();
        result.appendData("bean", bean);
        return result;
    }

    /**
     * 创建新对象
     * @param entity
     * @return
     */
    @PostMapping("")
    public RequestResult create(@RequestBody T entity, HttpServletRequest request){
        RequestResult result = new RequestResult();
        beforeCreate(entity, request, result);
        // 校验失败，可以提前返回结果
        if(result.getCode() != StatusCode.Success){
            return result;
        }

        getService().create(entity);
        result.appendData("id", entity.getId());
        afterCreate(entity, request, result);

        return result;
    }

    /**
     * 更新对象
     * @param entity
     * @return
     */
    @PutMapping("")
    public RequestResult update(@RequestBody T entity, HttpServletRequest request){
        RequestResult result = new RequestResult();
        beforeUpdate(entity, request, result);
        // 校验失败，可以提前返回结果
        if(result.getCode()!= StatusCode.Success){
            return result;
        }

        getService().update(entity);
        result.appendData("id", entity.getId());
        afterUpdate(entity, request, result);

        return result;
    }

    /**
     * 根据ID删除
     * @param ids
     *          可以是单个id值，也可以是id列表，多个id之间用下划线连接
     * @return
     */
    @DeleteMapping("/{ids}")
    public RequestResult delete(@PathVariable("ids") String ids, HttpServletRequest request){
        RequestResult result = new RequestResult();
        String[] idList = ids.split("_");
        beforeDelete(idList, request, result);
        // 校验失败，可以提前返回结果
        if(result.getCode() != StatusCode.Success){
            return result;
        }
        if(idList.length == 0){
            return result;
        }

        // 在Service中可能要操作缓存，@CacheEvict只有在被Controller直接调用时才会生效
        // 所有这里我们单独判断一下是否为单个ID删除
        if(idList.length == 1){
            getService().delete(Integer.valueOf(idList[0]));
        }else{
            getService().delete(idList);
        }

        return new RequestResult();
    }

    /**
     * 回调函数，在执行列表查询之前调用，可以修改过滤条件及排序条件
     *
     * @param selector
     *            添加过滤条件，如：<br/>
     *            selector.eq("status", 1)  <br/>
     *            selector.notEq("status", -1) <br/>
     *            selector.like("username", "san") <br/>
     *            <br/>
     * @param pageParams
     *            分页参数
     * @param request
     * @return
     */
    protected void beforeList(Selector selector, PageParams pageParams, HttpServletRequest request) {
    }

    /**
     * 回调函数，在执行列表查询之后调用
     * @param entityList
     * @param pageParams
     * @param request
     * @param result
     */
    protected void afterList(List<T> entityList, PageParams pageParams, HttpServletRequest request, RequestResult result) {
    }

    /**
     * 回调函数：在保存新对象之前调用，可以继续设置entity属性
     * @param entity
     * @param request
     * @param result   如果返回值中状态码不为0，则将提前返回结果
     */
    protected void beforeCreate(T entity, HttpServletRequest request, RequestResult result) {
    }

    /**
     * 回调函数：在保存新对象之后调用，可以修改返回视图
     * @param entity
     * @param request
     * @param result
     */
    protected void afterCreate(T entity, HttpServletRequest request, RequestResult result) {
    }

    /**
     * 回调函数：在更新对象之前调用，可以继续设置entity属性
     * @param entity
     * @param request
     * @param result 如果返回值中状态码不为0，则将提前返回结果
     */
    protected void beforeUpdate(T entity, HttpServletRequest request, RequestResult result) {
    }

    /**
     * 回调函数：在更新对象之后调用，可以修改返回视图
     * @param entity
     * @param request
     * @param result
     */
    protected void afterUpdate(T entity, HttpServletRequest request, RequestResult result) {
    }

    /**
     * 回调函数：在删除对象之前调用，可以校验用户权限
     * @param idList
     * @param request
     * @param result 如果返回值中状态码不为0，则将提前返回结果
     */
    protected void beforeDelete(String[] idList, HttpServletRequest request, RequestResult result) {
    }

    /**
     * 解析查询参数
     * @param selector
     * @param search
     */
    protected void parseSearch(Selector selector, String search){
        parseSearch(selector, search, null);
    }

    /**
     * 解析查询参数，指定表名
     * @param selector
     * @param search
     * @param tableName
     */
    protected void parseSearch(Selector selector, String search, String tableName) {
        if (StringUtils.isNotBlank(search)) {
            try {
                search = new String(Base64.decodeBase64(search), "UTF-8");
                selector.parseSearch(search, tableName);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取字符串参数
     * @param request
     * @param name
     * @return
     */
    protected String paramterStr(HttpServletRequest request, String name) {
        return request.getParameter(name);
    }

    /**
     * 获取整型参数
     * @param request
     * @param name
     * @return
     */
    protected Integer paramterInt(HttpServletRequest request, String name) {
        String str = paramterStr(request, name);
        return StringUtils.isBlank(str) ? null : Integer.valueOf(str);
    }

    /**
     * 获取长整型参数
     * @param request
     * @param name
     * @return
     */
    protected Long paramterLong(HttpServletRequest request, String name) {
        String str = paramterStr(request, name);
        return StringUtils.isBlank(str) ? null : Long.valueOf(str);
    }

    /**
     * 获取单精度浮点型参数
     * @param request
     * @param name
     * @return
     */
    protected Float paramterFloat(HttpServletRequest request, String name) {
        String str = paramterStr(request, name);
        return StringUtils.isBlank(str) ? null : Float.valueOf(str);
    }

    /**
     * 获取双精度浮点型参数
     * @param request
     * @param name
     * @return
     */
    protected Double paramterDouble(HttpServletRequest request, String name) {
        String str = paramterStr(request, name);
        return StringUtils.isBlank(str) ? null : Double.valueOf(str);
    }

    /**
     * 获取布尔型参数
     * @param request
     * @param name
     * @return
     */
    protected Boolean paramterBoolean(HttpServletRequest request, String name) {
        String str = paramterStr(request, name);
        return StringUtils.isBlank(str) ? null : Boolean.valueOf(str);
    }

    /**
     * 获取日期参数
     * @param request
     * @param name
     * @param format
     * @return
     */
    protected Date paramterDate(HttpServletRequest request, String name, String format) {
        String str = paramterStr(request, name);
        return StringUtils.isBlank(str) ? null : DateUtils.parse(str, format);
    }
}